﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using devtm.AutoMapper.CustomCode.TemplateAdd;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Modeling.Diagrams;
using CodeDomHelper.Types;
using devtm.Editor.TypeSelector;

namespace devtm.AutoMapper
{
    public partial class MappingModel : IFilePath
    {




        #region Namespace

        string NamespaceStr = string.Empty;
        internal string GetNamespaceValue()
        {

            if (!string.IsNullOrEmpty(NamespaceStr))
                return NamespaceStr;

            string  n = Store2DTE.GetDefaultNamespace(this.Store);

            if (!string.IsNullOrEmpty(n))
                NamespaceStr = n;

            return NamespaceStr;

        }



        internal void SetNamespaceValue(string newValue)
        {
            NamespaceStr = newValue;
        }

        #endregion


        public HashSet<String> GetNamespaces
        {
            get
            {
                HashSet<String> namespaces = new HashSet<string>();

                namespaces.Add(Namespace);

                foreach (UsingNamespace item in Namespaces)
                    if (!namespaces.Contains(item.Fullname))
                        namespaces.Add(item.Fullname);

                return namespaces;
            }
        }


        //internal IEnumerable<Type> GetTypes()
        //{

        //    HashSet<string> namespaces = GetNamespaces;

        //    foreach (Type item in ContainerTypes.GetFromReference(Store, namespaces))            
        //        yield return item;

        //    foreach (Type item in  ContainerTypes.GetFromSolution<Object>(Store, namespaces))
        //        yield return item;

        //}


        // System.Collections.Generic.IEnumerable`1[[MappingTest.Sources.ClassTest3, MappingTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
        internal Type FindType(string typeName)
        {

            return Helpers.FindType(typeName, Store, GetNamespaces);

        }


        internal TypeElement FindTypeElementByClass(string type)
        {

            foreach (var item in this.Elements)
                if (item.AssemblyQualifiedName == type)
                    return item;

            return null;
        }


        internal Mapper FindMapperFor(ItemMap itemMap)
        {

            string source =
                itemMap.SourceIsEnumerable
                    ? itemMap.SourceItemType
                    : itemMap.SourceType;

            string target =
                itemMap.TargetIsEnumerable
                    ? itemMap.TargetItemType
                    : string.IsNullOrEmpty(itemMap.TargetAs)
                        ? itemMap.TargetType
                        : itemMap.TargetAs;

            var s = BuildTypeExpression.Analyse(source);
            var t = BuildTypeExpression.Analyse(target);

            var s1 = s.IsGeneric
                ? s.SubType.TypeName
                : s.TypeName;

            var t1 = t.IsGeneric
                ? t.SubType.TypeName
                : t.TypeName;

            s = BuildTypeExpression.Analyse(s1);
            t = BuildTypeExpression.Analyse(t1);

            s1 = s.AssemblyQualifiedNameShort;
            t1 = t.AssemblyQualifiedNameShort;

            foreach (var item in this.Mappers)
                if (item.MappingSource != null && item.MappingDestination != null)
                    if (item.MappingSource.TypeElement.AssemblyQualifiedNameUltraShort == s1 && item.MappingDestination.TypeElement.AssemblyQualifiedNameUltraShort == t1)
                        return item;

            return null;

        }


        /// <summary>
        /// Find Mapper in other store
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        internal Mapper FindExternalMapperFor(string p)
        {

            Microsoft.VisualStudio.Modeling.Store store = null;

            Mapper mapper = null;

            string[] _select = ((string)p).Split('!');

            if (_select.Length == 2)
            {
                // get Project item for the filename
                var modelProjectItem = Store2DTE.GetOtherModels(Store).FirstOrDefault(c => c.Name == _select[0]);

                if (modelProjectItem != null)
                {
                    // load the store
                    store = StoreHelper.GetStore(modelProjectItem);

                    var e = store.ElementDirectory;
                    if (e != null)
                    {
                        // get the root model
                        MappingModel model = e.AllElements.FirstOrDefault() as MappingModel;
                        if (model != null)
                            mapper = model.Mappers.FirstOrDefault(c => c.Name == _select[1]);

                    }
                }

            }

            return mapper;

        }


        internal Mapper FindMapperFor(string typeSource, string typeTarget)
        {

            var s = BuildTypeExpression.Analyse(typeSource);
            var t = BuildTypeExpression.Analyse(typeTarget);

            foreach (var item in this.Mappers)
                if (item.MappingSource != null && item.MappingDestination != null)
                    if (item.MappingSource.TypeElement.AssemblyQualifiedName == s.TypeName && item.MappingDestination.TypeElement.AssemblyQualifiedName == t.TypeName)
                        return item;

            return null;

        }

        internal Mapper FindMapperFor(string typeSource)
        {

            var s = BuildTypeExpression.Analyse(typeSource);

            foreach (var item in this.Mappers)
                if (item.MappingSource != null && item.MappingDestination != null)
                    if (item.MappingSource.TypeElement.AssemblyQualifiedName == s.TypeName)
                        return item;

            return null;
        
        }

        internal TypeElement FindElementFor(string type)
        {

            foreach (TypeElement item in this.Elements)
                if (item.AssemblyQualifiedName == type)
                    return item;

            return null;
        }

        internal void CreateMapper()
        {

            try
            {

                using (CustomTypeRepository repository = CustomTypeRepository.Instance(Store, false))
                {

                    AddMapRoot frm = new AddMapRoot();

                    frm.SetList(this, repository);

                    if (frm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {

                        LinkPolicy policy = new LinkPolicy();

                        int ii = frm.ComboMatchProperty.SelectedIndex;

                        if (ii == 0)
                            policy.Mode = MatchingModel.MatchCaseSensitive;
                        else                        
                            policy.Mode = MatchingModel.MatchCaseUnsensitive;
                        

                        NewMapperHelper.CreateMapper(this, frm.SourceType.AssemblyQualifiedName, frm.TargetType.AssemblyQualifiedName, true, policy, null, repository);

                        if (frm.CreateBack)
                            NewMapperHelper.CreateMapper(this, frm.TargetType.AssemblyQualifiedName, frm.SourceType.AssemblyQualifiedName, true, policy, null, repository);

                    }

                }

            }
            catch (Exception ex)
            {

                devtm.AutoMapper.Helpers._output.WriteLine(ex.Message);

                throw;
            }

        }

        public string FilePath { get; set; }

        public bool ContainsPool { get; set; }

    }
}
